package com.ktdaddy.manager;

import com.github.pagehelper.PageHelper;
import com.ktdaddy.enums.WhaleErrorCode;
import com.ktdaddy.exception.BusinessRuntimeException;
import com.ktdaddy.mapper.PermissionMapper;
import com.ktdaddy.mapper.RolePermissionRelMapper;
import com.ktdaddy.pojo.Permission;
import com.ktdaddy.pojo.RolePermissionRel;
import com.ktdaddy.request.CreateRoleReq;
import com.ktdaddy.request.UpdateRoleReq;
import com.ktdaddy.vo.RoleInfoVO;
import com.ktdaddy.mapper.KernelRoleRelMapper;
import com.ktdaddy.mapper.RoleMapper;
import com.ktdaddy.pojo.KernelRoleRel;
import com.ktdaddy.pojo.Role;
import com.ktdaddy.request.RoleQueryReq;
import com.ktdaddy.utils.PageResult;
import com.ktdaddy.vo.RolePermVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author kdaddy@163.com
 * @date 2021/7/15 23:31
 */
@Component
public class RoleManager extends BaseManager{

    @Resource
    private KernelRoleRelMapper kernelRoleRelMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private PermissionMapper permissionMapper;

    @Resource
    private RolePermissionRelMapper rolePermissionRelMapper;

    /**
     * 根据关键用户信息查询角色
     * @param kernelId
     * @return
     */
    public List<RoleInfoVO> findRoleByKernelId(Integer kernelId) {
        Example example = new Example(KernelRoleRel.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("kernelId",kernelId);
        List<KernelRoleRel> kernelRoleRelList = kernelRoleRelMapper.selectByExample(example);

        List<Integer> roleIds = kernelRoleRelList.stream().map(KernelRoleRel::getRoleId).collect(Collectors.toList());
        List<RoleInfoVO> roleInfoBOS = new ArrayList<>();

        if(CollectionUtils.isEmpty(roleIds)){
            return roleInfoBOS;
        }

        Example roleExample = new Example(Role.class);
        Example.Criteria roleCriteria = roleExample.createCriteria();
        roleCriteria.andIn("id",roleIds);
        List<Role> roleList = roleMapper.selectByExample(roleExample);

        for(Role singleRole : roleList){
            RoleInfoVO roleInfoBO = new RoleInfoVO();
            BeanUtils.copyProperties(singleRole,roleInfoBO);
            roleInfoBOS.add(roleInfoBO);
        }

        return roleInfoBOS;
    }

    public PageResult getRoleListByPage(RoleQueryReq roleQueryReq) {
        PageHelper.startPage(roleQueryReq.getPage(), roleQueryReq.getPageSize());

        Example roleExample = new Example(Role.class);
        Example.Criteria roleCriteria = roleExample.createCriteria();
        roleCriteria.andEqualTo("roleName",roleQueryReq.getRoleName());
        roleCriteria.andEqualTo("status",roleQueryReq.getStatus());
        List<Role> roleList = roleMapper.selectByExample(roleExample);

        List<RolePermVO> rolePermVOList = bindingPerm(roleList);

        return setterPagedGrid(rolePermVOList, roleQueryReq.getPage());
    }

    /**
     * 查询绑定的权限信息
     * @param roleList
     * @return
     */
    private List<RolePermVO> bindingPerm(List<Role> roleList) {
        List<RolePermVO> result = new ArrayList<>();
        if(CollectionUtils.isEmpty(roleList)){
            return result;
        }
        for(Role role : roleList){
            RolePermVO rolePermVO = new RolePermVO();
            Example rolePermExample = new Example(RolePermissionRel.class);
            Example.Criteria rolePermCriteria = rolePermExample.createCriteria();
            rolePermCriteria.andEqualTo("roleId",role.getId());
            List<Integer> permIds = rolePermissionRelMapper.selectByExample(rolePermExample).stream().map(RolePermissionRel::getPermissionId).collect(Collectors.toList());
            permIds = fetchMinimum(permIds);

            BeanUtils.copyProperties(role,rolePermVO);
            rolePermVO.setMenuIds(permIds);
            result.add(rolePermVO);
        }
        return result;
    }

    /**
     * 获取最底层的子节点
     * @param permIds
     * @return
     */
    private List<Integer> fetchMinimum(List<Integer> permIds) {
        List<Integer> result = new ArrayList<>();
        if(CollectionUtils.isEmpty(permIds)){
            return result;
        }

        for (Integer permId : permIds){
            Example permExample = new Example(Permission.class);
            Example.Criteria permCriteria = permExample.createCriteria();
            permCriteria.andEqualTo("parentId",permId);
            List<Permission> list = permissionMapper.selectByExample(permExample);
            //如果不存在子节点了，当前节点即为最终节点信息
            if(CollectionUtils.isEmpty(list)){
                result.add(permId);
            }
        }
        return result;
    }

    public Integer saveRole(CreateRoleReq createRoleReq) {
        Role role = new Role();
        BeanUtils.copyProperties(createRoleReq,role);
        int result = roleMapper.insertSelective(role);
        if(result < 1){
            throw new BusinessRuntimeException(WhaleErrorCode.DB_INSERT_ERROR);
        }
        return role.getId();
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer saveRoleAndBuildPermission(CreateRoleReq createRoleReq) {
        //保存角色
        int roleId = saveRole(createRoleReq);

        //保存角色权限关系
        buildRolePermission(roleId,createRoleReq.getMenu());
        return roleId;
    }

    private void buildRolePermission(int roleId, List<Integer> menu) {
        Example permissionExample = new Example(Permission.class);
        Example.Criteria permissionCriteria = permissionExample.createCriteria();
        permissionCriteria.andIn("id",menu);
        List<Permission> permissionList = permissionMapper.selectByExample(permissionExample);
        Role role = roleMapper.selectByPrimaryKey(roleId);

        if(!CollectionUtils.isEmpty(permissionList) && !Objects.isNull(role)){
            for(Permission permission : permissionList){
                RolePermissionRel rolePermissionRel = new RolePermissionRel();
                rolePermissionRel.setPermissionCode(permission.getPermissionCode());
                rolePermissionRel.setPermissionId(permission.getId());
                rolePermissionRel.setRoleCode(role.getRoleCode());
                rolePermissionRel.setRoleId(roleId);
                rolePermissionRel.setRoleName(role.getRoleName());
                rolePermissionRelMapper.insertSelective(rolePermissionRel);
            }
        }
    }

    public Role findRoleByName(String roleName) {
        Example roleExample = new Example(Role.class);
        Example.Criteria roleCriteria = roleExample.createCriteria();
        roleCriteria.andEqualTo("roleName",roleName);
        Role role = roleMapper.selectOneByExample(roleExample);
        return role;
    }

    public Role findRoleByCode(String roleCode){
        Example roleExample = new Example(Role.class);
        Example.Criteria roleCriteria = roleExample.createCriteria();
        roleCriteria.andEqualTo("roleCode",roleCode);
        Role role = roleMapper.selectOneByExample(roleExample);
        return role;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteRoleById(Integer id) {
        //物理删除角色
        int result = roleMapper.deleteByPrimaryKey(id);
        if(result < 1){
            throw new BusinessRuntimeException(WhaleErrorCode.DB_DELETE_ERROR);
        }
        //物理删除角色权限关系
        Example rolePermExample = new Example(RolePermissionRel.class);
        Example.Criteria rolePermCriteria = rolePermExample.createCriteria();
        rolePermCriteria.andEqualTo("roleId",id);
        rolePermissionRelMapper.deleteByExample(rolePermExample);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateRoleAndResetPermission(UpdateRoleReq updateRoleReq) {
        //更新角色
        int roleId = updateRole(updateRoleReq);

        //删除原有角色权限关系
        deleteRolePermission(roleId);

        //保存角色权限关系
        buildRolePermission(roleId,updateRoleReq.getMenu());
    }

    private void deleteRolePermission(int roleId) {
        Example rolePermExample = new Example(RolePermissionRel.class);
        Example.Criteria rolePermCriteria = rolePermExample.createCriteria();
        rolePermCriteria.andEqualTo("roleId",roleId);
        rolePermissionRelMapper.deleteByExample(rolePermExample);
    }

    private int updateRole(UpdateRoleReq updateRoleReq) {
        Role role = roleMapper.selectByPrimaryKey(updateRoleReq.getId());
        BeanUtils.copyProperties(updateRoleReq,role);
        roleMapper.updateByPrimaryKey(role);
        return role.getId();
    }

    public Role getById(Integer id) {
        return roleMapper.selectByPrimaryKey(id);
    }

    public boolean setRoleStatus(Integer id, Integer status) {
        Role role = roleMapper.selectByPrimaryKey(id);
        role.setStatus(status);
        int result = roleMapper.updateByPrimaryKey(role);
        if(result < 1){
            throw new BusinessRuntimeException(WhaleErrorCode.DB_UPDATE_ERROR);
        }
        return true;
    }

    public List<RoleInfoVO> queryList(String roleName, Integer status) {
        List<RoleInfoVO> result = new ArrayList<>();
        Example roleExample = new Example(Role.class);
        Example.Criteria rolePermCriteria = roleExample.createCriteria();
        if(StringUtils.isNotBlank(roleName)){
            rolePermCriteria.andEqualTo("roleName",roleName);
        }
        if(!Objects.isNull(status) && status > 0){
            rolePermCriteria.andEqualTo("status",status);
        }
        List<Role> roleList = roleMapper.selectByExample(roleExample);

        if(!CollectionUtils.isEmpty(roleList)){
            for(Role role : roleList){
                RoleInfoVO roleInfoVO = new RoleInfoVO();
                BeanUtils.copyProperties(role,roleInfoVO);
                roleInfoVO.setCreateTime(role.getTimeCreated());
                result.add(roleInfoVO);
            }
        }
        return result;
    }
}
